package com.spring.security.service.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.spring.security.entity.User;
import com.spring.security.service.JwtService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;

/**
 * @author HouKunLin
 */
@Service
public class JwtServiceImpl implements JwtService, InitializingBean {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.issuer}")
    private String issuer;

    @Value("${jwt.subject}")
    private String subject;

    private Algorithm algorithm;

    private JWTVerifier verifier;

    @PostConstruct
    public void post() {
        algorithm = Algorithm.HMAC256(secret);
        verifier = JWT.require(algorithm).build();
    }

    @Override
    public String sign(User user) throws JWTCreationException {
        return buildSign(user).sign(algorithm);
    }

    @Override
    public String sign(User user, String secret) throws JWTCreationException {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        return buildSign(user).sign(algorithm);
    }

    /**
     * 构建签名内容
     *
     * @param user
     * @return
     */
    private JWTCreator.Builder buildSign(User user) {
        long expireTime = 60 * 60 * 24 * 2 * 1000;
        Date now = new Date();
        return JWT.create()
                .withClaim("id", user.getId())
                .withClaim("username", user.getUsername())
                .withClaim("nick", user.getUsername())
                .withExpiresAt(new Date(now.getTime() + expireTime))
                .withIssuer(issuer)
                .withIssuedAt(now)
                .withSubject(subject);
    }

    @Override
    public boolean verify(String token) {
        try {
            decodedJWT(token);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    @Override
    public boolean verify(String token, String secret) {
        try {
            decodedJWT(token, secret);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    @Override
    public DecodedJWT decodedJWT(String token) throws JWTVerificationException {
        return verifier.verify(token);
    }

    @Override
    public DecodedJWT decodedJWT(String token, String secret) throws JWTVerificationException {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier verifier = JWT.require(algorithm).build();
        return verifier.verify(token);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (secret == null || secret.trim().isEmpty()) {
            throw new Exception("JWT secret 不能为空");
        }
        secret = secret.trim();

        if (issuer == null || issuer.trim().isEmpty()) {
            throw new Exception("JWT issuer 不能为空");
        }
        issuer = issuer.trim();

        if (subject == null || subject.trim().isEmpty()) {
            throw new Exception("JWT subject 不能为空");
        }
        subject = subject.trim();
    }
}
